package com.ctrip.cap.page;

import io.appium.java_client.AppiumDriver;
import io.appium.java_client.pagefactory.AppiumFieldDecorator;
import io.appium.java_client.pagefactory.AppiumFieldDecorator.FieldInteceptor;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.LoadableComponent;

import com.ctrip.cap.CapLogger;

/**
 * Page Object Pattern实践，Page Object通过Decorate Page Field来优化编程方式。
 * 使用时，注意页面加载完成的判断，重写isLoadded方法。当然你可以不这么做<br>
 * 比如Maven Archetype 中的LoginPage
 * 
 * <pre class="code">
 * public class LoginPage extends CapPage&lt;LoginPage&gt; {
 * 
 * 	public LoginPage(WebDriver driver) {
 * 		super(driver);
 * 	}
 * 
 * 	&#064;AndroidFindBy(className = &quot;android.widget.EditText&quot;)
 * 	private List&lt;WebElement&gt; namePassword;
 * 
 * 	&#064;FindBy(id = &quot;ctrip.android.view:id/button_login_update&quot;)
 * 	private WebElement login;
 * 
 * 	public LoginPage inputNamePwd(String user, String pwd) {
 * 
 * 		WebElement userName = namePassword.get(0);
 * 		userName.clear();
 * 		userName.sendKeys(user);
 * 
 * 		WebElement password = namePassword.get(1);
 * 		password.clear();
 * 		password.sendKeys(pwd);
 * 
 * 		return this;
 * 	}
 * 
 * 	public LoginPage login() {
 * 		login.click();
 * 		return this;
 * 	}
 * }
 * </pre>
 * 
 * @author ltyao
 * @param <T>
 */
public class CapPage<T extends LoadableComponent<T>> extends
		LoadableComponent<T> {

	public static long globalImplicitlyWaitInSeconds = 6;

	private AppiumFieldDecorator afd;

	protected AppiumDriver driver;

	public CapPage(WebDriver driver) {
		this.driver = (AppiumDriver) driver;
		afd = new AppiumFieldDecorator(driver);
		afd.resetImplicitlyWaitTimeOut(globalImplicitlyWaitInSeconds,
				TimeUnit.SECONDS);
		afd.setFieldInteceptor(new LogInterceptor());
		PageFactory.initElements(afd, this);
	}

	/**
	 * 如果未加载，调用此方法，但通常如果使用Wait，Override isLoaded方法即可。
	 */
	@Override
	protected void load() {

	}

	/**
	 * 判断此Page是否加载完全，如果未加载，throw 一个Error的子类
	 */
	@Override
	protected void isLoaded() throws Error {

	}

	public void setImplicitlyWaitTimeOut(long timeOut, TimeUnit timeUnit) {
		afd.resetImplicitlyWaitTimeOut(timeOut, timeUnit);
	}

	public void setLogInterceptor(FieldInteceptor interceptor) {
		if (interceptor != null) {
			afd.setFieldInteceptor(interceptor);
		}
	}

	static class LogInterceptor implements FieldInteceptor {

		static final List<String> whiteMethods = Arrays.asList("toString");

		@Override
		public void pre(By by, Method method) {
			if (whiteMethods.contains(method.getName())) {
				return;
			}
			String message = String.format(
					"Try to do %s on element which located by %s",
					method.getName(), by);
			CapLogger.step(message);

		}

	}

}
